package com.baidu.lenovo.autotest;

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.baidu.aip.asrwakeup3.core.util.FileUtil;
import com.baidu.tts.auth.AuthInfo;
import com.baidu.tts.chainofresponsibility.logger.LoggerProxy;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.TtsMode;


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * 除了SDK，该类没有任何依赖，可以直接复制进你的项目
 * <p>
 * 默认TEMP_DIR = "/sdcard/baiduTTS"; // 重要！请手动将assets目录下的3个dat 文件复制到该目录
 * 确保 TEXT_FILENAME 和 MODEL_FILENAME 存在
 *
 */

public class TTSActivity extends AppCompatActivity {

    private static final String TEXT = "欢迎使用百度语音合成，请在代码中修改合成文本";
//    String stringArray[]={"放首歌","播放老狼的同桌的你","播放风吹麦浪","方大同的歌","奶茶有什么歌","爱有万分之一甜是哪首歌里的","播放我导入的歌单","从百度导入的歌单","播放新歌","来点热歌","播个跑步的歌曲","轻音乐","欢快的英文歌曲","这首歌是谁唱的　","这首歌是哪个专辑的","这首歌叫什么名字","收藏这首歌　","取消收藏","这首歌","播放我的收藏列表","下一首","暂停","继续","上一首","随机播放歌单　","单曲循环这首歌　","取消单曲循环","顺序播放歌单","喜欢这首歌","我不喜欢这首歌","播放山丘","换个版本","播放许嵩的歌","有没有中国风的","我要胡彦斌版的","不要任素汐版的","放首歌","要相似的歌","放首歌","他的其它歌","查看我的播放历史","查看当前播放列表","查看音乐收藏列表","我想看老狼的歌","查看热歌榜","播放第三首","我想听倒数第1首","取消收藏","第三首","收藏","第三首","播放小说","我要听评书","我想听单口相声","播放儿童故事","给我播一个热门的小品","播放最近更新的有声书","来一个最火的小说","播放郭德纲的相声","播放聊斋全集","我想听十点读书","放德云社最新相声的驸马爷","放放郭冬临的经典小品集","听一段摸金天师的第1集","放一下雪中悍刀行的第4集","播放爱探险的朵拉第2集","放一放凶宅风水师第1集饭店命案","播放周建龙的盗墓笔记第9集","播放我订阅的节目","下一个专辑","上一个专辑","换一个专辑","下一个","上一个","下个节目","跳到第21集","快进","快退","快进50秒","快退10秒","暂停","继续播放","继续","播放","停止","订阅","取消订阅","这个主播是谁","谁在播讲","播讲人的名字","现在播的专辑叫什么","这是什么专辑","专辑的名字","这是什么节目","现在在播什么","节目叫什么","播到第几集了","第几集了","这是哪一集","这个专辑更新了吗","播放小说鬼吹灯","查看播放列表","查看我的订阅列表","查看周建龙的有声书","播放第三个","取消收藏","订阅第三个","收藏","订阅第三个","我要听汕头电台音乐之声","我想听山东经济广播","我要听上海五星体育广播","播放fm101.8","播放辽宁调频97.5","我想听新闻频道","来一个音乐的频道","放一个交通类广播","播放北京台","播放一下福建的电台","听听辽宁的广播","播放上海音乐台","听听中国的国际电台频道","播放漳州综合广播电台","播放邯郸的新闻广播","播放广播","下一个","上一个","现在播放的是什么台","停止播放","继续播放","我想看比利林恩的中场战事","播放第2个","我要看电视剧","播放第4个","何炅主持的综艺节目","播放第4个","最近热映的电影","播放第一个","大话西游第一部","播放","返回","我要看人民的名义第2集","下一集","上一集","第2集","退出","我想看白浅","播放第一个","播放","进入静音","暂停当前视频","播放当前视频","快进2分钟","快退3分钟","从第1小时处开始播放","播放新闻","关闭静音","今天有什么新闻","我想听科技新闻","上海的热门新闻","播放下一条","切换","上一条","暂停","继续播放","今天天气","上海今天天气","未来四天天气","未来半个月天气如何","北京今天多少度","今天最高温度","今天热吗","北京明天的风力","今天适合穿什么衣服","今天适合洗车吗","今天适合运动吗","今天适合旅游吗","今天容易感冒吗","今天紫外线强吗","今天比昨天冷吗","北京比上海哪个冷","讲个笑话","图片笑话","儿童笑话","再来一个","下一个","上一个笑话","暂停","继续","笑话","声音小一点","静音","取消静音模式","倒计时5分钟","删除明天早上的闹钟","删除倒计时","明天早上我有哪些闹钟","我有哪些倒计时","我想看短视频","我想看小猫搞笑视频","科技视频","舞蹈教学","学跳广场舞","广场舞凤凰传奇","少儿舞蹈","宝宝学跳舞","大王叫我来巡山的舞蹈视频","娱乐视频","我要看张韶涵","春节联欢晚会黄渤的跳舞","凤凰传奇的演唱会","我想看相声","我要看郭德纲","我要看冯巩的小品","小品吃面","沈腾的小品","我想看东北二人转","游戏视频","王者荣耀视频","我要看mv","我要看邓丽君的mv","大王叫我来巡山mv视频","一人饮酒醉的mv","海阔天空的mv","体育视频","足球视频","我想看NBA","健身操","太极拳","减肥瑜伽","戏曲穆桂英挂帅","京剧选段","京剧","京剧霸王别姬","黄梅戏刘三姐","黄梅戏女驸马选段","女驸马黄梅戏","看豫剧","豫剧红楼梦","河南豫剧","播放晋剧打金枝","晋剧","我想看评剧","我想看评剧刘巧儿","评剧杨三姐告状","昆曲","秦腔三娘教子","秦腔李淑芳唱段","美食视频","美妆视频","我想看维密走秀","看走秀","美女走秀","编发教程","播放怎么折纸","三个火是什么字","大王的王的笔画数","大王的王的笔顺","美好的美还可以组什么词","大王的王的偏旁部首","五行属土的有哪些","坏的反义字","美好的近义词","觊觎的意思","不但而且造句","一马当先的意思","盛气凌人的凌是什么意思","aabc式的成语","积极向上的名言警句","静夜思全文","念一首李白的诗","静夜思全文","静夜思翻译","静夜思的第二句","李白有哪些诗","珠穆朗玛峰多高","查询巧克力热量","新疆特产","抽空去看看打一成语","为什么眼泪是咸的","纽约现在是星期几","今天是农历几号","纽约的时区","春节的放假安排","国庆放假安排","2+5等于几","根号3等于多少","翻译一下我想你","翻译下apple","北京限行","美元汇率","上证指数","百度股价","李彦宏是谁","故宫的百科","大象图片","今日双色球号码","狮子座和白羊座配对吗"};
    String stringArray[]={"浙江今天温度。","安静的静的反义词。","因为遇见你。","现在一美元等于多少人民币？","一欧元等于多少人民币？"};

    // ================== 初始化参数设置开始 ==========================
    /**
     * 发布时请替换成自己申请的appId appKey 和 secretKey。注意如果需要离线合成功能,请在您申请的应用中填写包名。
     * 本demo的包名是com.baidu.tts.sample，定义在build.gradle中。
     */
    protected String appId = "11005757";

    protected String appKey = "Ovcz19MGzIKoDDb3IsFFncG1";

    protected String secretKey = "e72ebb6d43387fc7f85205ca7e6706e2";

    // TtsMode.MIX; 离在线融合，在线优先； TtsMode.ONLINE 纯在线； 没有纯离线
    private TtsMode ttsMode = TtsMode.ONLINE;

    // ================选择TtsMode.ONLINE  不需要设置以下参数; 选择TtsMode.MIX 需要设置下面2个离线资源文件的路径
    private static final String TEMP_DIR = "/sdcard/baiduTTS"; // 重要！请手动将assets目录下的3个dat 文件复制到该目录

    // 请确保该PATH下有这个文件
    private static final String TEXT_FILENAME = TEMP_DIR + "/" + "bd_etts_text.dat";

    // 请确保该PATH下有这个文件 ，m15是离线男声
    private static final String MODEL_FILENAME =
            TEMP_DIR + "/" + "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";

    // ===============初始化参数设置完毕，更多合成参数请至getParams()方法中设置 =================

    protected SpeechSynthesizer mSpeechSynthesizer;

    // =========== 以下为UI部分 ==================================================

    private Button mSpeak;

    private Button mStop;

    private TextView mShowText;

    protected Handler mainHandler;
    String message="";
    Map asrMap;

    private static final String DESC = "精简版合成，仅给出示例集成合成的调用过程。可以测试离线合成功能，首次使用请联网。\n"
            + "其中initTTS方法需要在新线程调用，否则引起UI阻塞。\n"
            + "纯在线请修改代码里ttsMode为TtsMode.ONLINE， 没有纯离线。\n"
            + "离线功能需要手动将assets目录下的资源文件复制到TEMP_DIR =/sdcard/baiduTTS \n"
            + "完整的SDK调用方式可以参见MainActivity\n\n";


    private static final String TAG = "MiniActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mini);
        asrMap=readFileMap("baiduASRResult.txt");
        initView();
        initPermission();
        initTTs();
    }
    public void save(String s,String file) {
        File ttsFile;
        BufferedOutputStream ttsFileBufferedOutputStream;
        String tmpDir = FileUtil.createTmpDir(this);
        String filename = file + System.currentTimeMillis()+ ".txt";
        // 保存的语音文件是 16K采样率 16bits编码 单声道 pcm文件。
        ttsFile = new File(tmpDir, filename);
        Log.i("zxx", "try to write audio file to " + ttsFile.getAbsolutePath());
        try {
            if (ttsFile.exists()) {
                ttsFile.delete();
            }
            ttsFile.createNewFile();
            // 创建FileOutputStream对象
            FileOutputStream ttsFileOutputStream = new FileOutputStream(ttsFile);
            // 创建BufferedOutputStream对象
            ttsFileBufferedOutputStream = new BufferedOutputStream(ttsFileOutputStream);
            ttsFileBufferedOutputStream.write(s.getBytes());
            ttsFileBufferedOutputStream.flush();
            ttsFileBufferedOutputStream.close();

        } catch (IOException e) {
            // 请自行做错误处理
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    private Map readFileMap(String name)
    {String sampleDir = "baiduTTS";
        String tmpDir = Environment.getExternalStorageDirectory().toString() + "/" + sampleDir;

        String filename =tmpDir+ "/"+name;
        File file=new File(filename);
        Map<Long, String> map = new TreeMap<Long, String>();
        String content = "";
        String regex = ";time=";
        try
        {
            InputStream stream = new FileInputStream(file);
//            InputStream stream = getResources().getAssets().open(name);
            if (stream != null)
            {
                InputStreamReader reader = new InputStreamReader(stream);
                BufferedReader bufferedReader = new BufferedReader(reader);
                String line;
                while ((line = bufferedReader.readLine()) != null)
                {
                    content += line + "\n";
                    Log.i("zxx", content);

                    String[] array = line.split(regex);
//	        int endage = Integer.parseInt(array[1]);
                    long f = Long.parseLong(array[1]);

                    map.put(f, array[0]);
                }

                stream.close();
            }
        }
        catch (IOException e)
        {
            content = "";
        }

        return map;
    }

    /**
     * 注意此处为了说明流程，故意在UI线程中调用。
     * 实际集成中，该方法一定在新线程中调用，并且该线程不能结束。具体可以参考NonBlockSyntherizer的写法
     */
    private void initTTs() {
//        LoggerProxy.printable(true); // 日志打印在logcat中
        boolean isMix = ttsMode.equals(TtsMode.MIX);
        boolean isSuccess;
        if (isMix) {
            // 检查2个离线资源是否可读
            isSuccess = checkOfflineResources();
            if (!isSuccess) {
                return;
            } else {
                print("离线资源存在并且可读, 目录：" + TEMP_DIR);
            }
        }
        // 日志更新在UI中，可以换成MessageListener，在logcat中查看日志
        SpeechSynthesizerListener listener = new UiMessageListener(mainHandler);

        // 1. 获取实例
        mSpeechSynthesizer = SpeechSynthesizer.getInstance();
        mSpeechSynthesizer.setContext(this);

        // 2. 设置listener
        mSpeechSynthesizer.setSpeechSynthesizerListener(listener);

        // 3. 设置appId，appKey.secretKey
        int result = mSpeechSynthesizer.setAppId(appId);
        checkResult(result, "setAppId");
        result = mSpeechSynthesizer.setApiKey(appKey, secretKey);
        checkResult(result, "setApiKey");

        // 4. 支持离线的话，需要设置离线模型
        if (isMix) {
            // 检查离线授权文件是否下载成功，离线授权文件联网时SDK自动下载管理，有效期3年，3年后的最后一个月自动更新。
            isSuccess = checkAuth();
            if (!isSuccess) {
                return;
            }
            // 文本模型文件路径 (离线引擎使用)， 注意TEXT_FILENAME必须存在并且可读
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
            // 声学模型文件路径 (离线引擎使用)， 注意TEXT_FILENAME必须存在并且可读
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);
        }

        // 5. 以下setParam 参数选填。不填写则默认值生效
        // 设置在线发声音人： 0 普通女声（默认） 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
        // 设置合成的音量，0-9 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "9");
        // 设置合成的语速，0-9 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");
        // 设置合成的语调，0-9 ，默认 5
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");

        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
        // 该参数设置为TtsMode.MIX生效。即纯在线模式不生效。
        // MIX_MODE_DEFAULT 默认 ，wifi状态下使用在线，非wifi离线。在线状态下，请求超时6s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线，非wifi离线。在线状态下， 请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_NETWORK ， 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线

        mSpeechSynthesizer.setAudioStreamType(AudioManager.MODE_IN_CALL);

        // x. 额外 ： 自动so文件是否复制正确及上面设置的参数
        Map<String, String> params = new HashMap<>();
        // 复制下上面的 mSpeechSynthesizer.setParam参数
        // 上线时请删除AutoCheck的调用
        if (isMix) {
            params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, TEXT_FILENAME);
            params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, MODEL_FILENAME);
        }
        InitConfig initConfig =  new InitConfig(appId, appKey, secretKey, ttsMode, params, listener);
        AutoCheck.getInstance(getApplicationContext()).check(initConfig, new Handler() {
            @Override
            /**
             * 开新线程检查，成功后回调
             */
            public void handleMessage(Message msg) {
                if (msg.what == 100) {
                    AutoCheck autoCheck = (AutoCheck) msg.obj;
                    synchronized (autoCheck) {
                        String message = autoCheck.obtainDebugMessage();
                        print(message); // 可以用下面一行替代，在logcat中查看代码
                        // Log.w("AutoCheckMessage", message);
                    }
                }
            }

        });

        // 6. 初始化
        result = mSpeechSynthesizer.initTts(ttsMode);
        checkResult(result, "initTts");

    }

    /**
     * 检查appId ak sk 是否填写正确，另外检查官网应用内设置的包名是否与运行时的包名一致。本demo的包名定义在build.gradle文件中
     *
     * @return
     */
    private boolean checkAuth() {
        AuthInfo authInfo = mSpeechSynthesizer.auth(ttsMode);
        if (!authInfo.isSuccess()) {
            // 离线授权需要网站上的应用填写包名。本demo的包名是com.baidu.tts.sample，定义在build.gradle中
            String errorMsg = authInfo.getTtsError().getDetailMessage();
            print("【error】鉴权失败 errorMsg=" + errorMsg);
            return false;
        } else {
            print("验证通过，离线正式授权文件存在。");
            return true;
        }
    }

    /**
     * 检查 TEXT_FILENAME, MODEL_FILENAME 这2个文件是否存在，不存在请自行从assets目录里手动复制
     *
     * @return
     */
    private boolean checkOfflineResources() {
        String[] filenames = {TEXT_FILENAME, MODEL_FILENAME};
        for (String path : filenames) {
            File f = new File(path);
            if (!f.canRead()) {
                print("[ERROR] 文件不存在或者不可读取，请从assets目录复制同名文件到：" + path);
                print("[ERROR] 初始化失败！！！");
                return false;
            }
        }
        return true;
    }

    private void speak(String s) {
        /* 以下参数每次合成时都可以修改
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
         *  设置在线发声音人： 0 普通女声（默认） 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5"); 设置合成的音量，0-9 ，默认 5
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5"); 设置合成的语速，0-9 ，默认 5
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5"); 设置合成的语调，0-9 ，默认 5
         *
         *  mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
         *  MIX_MODE_DEFAULT 默认 ，wifi状态下使用在线，非wifi离线。在线状态下，请求超时6s自动转离线
         *  MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线，非wifi离线。在线状态下， 请求超时1.2s自动转离线
         *  MIX_MODE_HIGH_SPEED_NETWORK ， 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线
         *  MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线，其它状态离线。在线状态下，请求超时1.2s自动转离线
         */

        if (mSpeechSynthesizer == null) {
            print("[ERROR], 初始化失败");
            return;
        }
        int result = mSpeechSynthesizer.speak(s);
        mShowText.setText("");
        print("合成并播放 按钮已经点击");
        checkResult(result, "speak");

    }

    private void stop() {
        print("停止合成引擎 按钮已经点击");
        int result = mSpeechSynthesizer.stop();
        checkResult(result, "stop");

    }

    //  下面是UI部分

    private void initView() {
        mSpeak = (Button) this.findViewById(R.id.speak);
        mStop = (Button) this.findViewById(R.id.stop);
        mShowText = (TextView) this.findViewById(R.id.showText);
        mShowText.setText(DESC);
//        View.OnClickListener listener = new View.OnClickListener() {
//            public void onClick(View v) {
//                int id = v.getId();
//                switch (id) {
//                    case R.id.speak:
//                        speak();
//                        break;
//                    case R.id.stop:
//                        stop();
//                        break;
//                    default:
//                        break;
//                }
//            }
//        };
        mSpeak.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                speak();//
                Set<Map.Entry<Long, String>> asr = asrMap.entrySet();

                Iterator<Map.Entry<Long, String>> asrit = asr.iterator();
                while (asrit.hasNext()) {

                    // 返回的是封装了key和value对象的Map.Entry对象
                    Map.Entry<Long, String> en1 = asrit.next();

                    // 获取Map.Entry对象中封装的key和value对象
                    Long key1 = en1.getKey();
                    String s = en1.getValue();
                    speak(s);
                    message += s;
                    message += "  ;time=" + System.currentTimeMillis();
                    message += "\n";
                    }
                save(message,"TTSResult");
            }
        });
        mStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stop();
            }
        });
        mainHandler = new Handler() {
            /*
             * @param msg
             */
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.obj != null) {
                    print(msg.obj.toString());
                }
            }

        };
    }

    private void print(String message) {
        Log.i(TAG, message);
        mShowText.append(message + "\n");
    }

    @Override
    protected void onDestroy() {
        if (mSpeechSynthesizer != null) {
            mSpeechSynthesizer.stop();
            mSpeechSynthesizer.release();
            mSpeechSynthesizer = null;
            print("释放资源成功");
        }
        super.onDestroy();
    }

    private void checkResult(int result, String method) {
        if (result != 0) {
            print("error code :" + result + " method:" + method + ", 错误码文档:http://yuyin.baidu.com/docs/tts/122 ");
        }
    }

    //  下面是android 6.0以上的动态授权

    /**
     * android 6.0 以上需要动态申请权限
     */
    private void initPermission() {
        String[] permissions = {
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.MODIFY_AUDIO_SETTINGS,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_SETTINGS,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_WIFI_STATE
        };

        ArrayList<String> toApplyList = new ArrayList<String>();

        for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
                // 进入到这里代表没有权限.
            }
        }
        String[] tmpList = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }

    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // 此处为android 6.0以上动态授权的回调，用户自行实现。
    }
}
